iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Modern Web

現在就學React.js 系列 第 18

綜合練習-TodoList 實作(下) Day18

  • 分享至 

  • xImage
  •  

今天就要來準備實作TodoList了,來看一下昨天的結果圖。
https://ithelp.ithome.com.tw/upload/images/20241002/20159895cIzJjAEUOQ.png

首先開一個新的專案

專案環境建立

使用 create-react-app 建立一個 React 專案

npx create-react-app todo-app
cd todo-app

由於用到 styled-components 套件來編寫樣式

npm install styled-components

App.js:主元件

App.js 是我們的主要邏輯元件,它負責管理所有的待辦事項,並透過 useState 來更新應用程式的狀態。接著它會將資料傳遞給 TodoListTodoForm 元件,讓這些元件負責渲染與互動。


import React, { useState } from 'react';
import styled, { createGlobalStyle } from 'styled-components';
import TodoList from './TodoList';
import TodoForm from './TodoForm';

const GlobalStyle = createGlobalStyle`
  body {
    font-family: 'Arial', sans-serif;
    background-color: #f0f4f8;
    margin: 0;
    padding: 0;
  }
`;

const Container = styled.div`
  max-width: 600px;
  margin: 50px auto;
  padding: 20px;
  background-color: #fff;
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  text-align: center;
`;

const Title = styled.h1`
  font-size: 2.5rem;
  color: #333;
  margin-bottom: 20px;
`;

const App = () => {
  const [todos, setTodos] = useState([
    { id: 1, text: '學習 React', completed: false },
    { id: 2, text: '完成作業', completed: false }
  ]);

  const addTodo = (text) => {
    setTodos([...todos, { id: Date.now(), text, completed: false }]);
  };

  const toggleComplete = (id) => {
    setTodos(
      todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };
  
  // 刪除待辦事項
  const deleteTodo = id => {
    setTodos(todos.filter(todo => todo.id !== id))
  }

  return (
    <Container>
      <GlobalStyle />
      <Title>待辦事項清單</Title>
      <TodoForm addTodo={addTodo} />
      <TodoList todos={todos} toggleComplete={toggleComplete} deleteTodo={deleteTodo} />
    </Container>
  );
};

export default App;

TodoList.js:待辦事項列表元件

TodoList 元件負責將待辦事項渲染出來,它接收 todos 陣列並根據每個待辦事項的狀態來決定是否顯示為已完成。


import React from 'react';
import Todo from './Todo';
import styled from 'styled-components';

const List = styled.ul`
  list-style: none;
  padding: 0;
`;

const TodoList = ({ todos, toggleComplete,deleteTodo }) => {
  return (
    <List>
      {todos.map(todo => (
        <Todo key={todo.id} todo={todo} toggleComplete={toggleComplete} deleteTodo={deleteTodo} />
      ))}
    </List>
  );
};

export default TodoList;

Todo.js:單一待辦事項元件

這個元件會接收 todo 物件與 toggleCompletedeleteTodo方法,並根據待辦事項的狀態來動態渲染按鈕和樣式。


import React from 'react';
import styled from 'styled-components';

const TodoItem = styled.li`
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  margin-bottom: 10px;
  background-color: #f9f9f9;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: background-color 0.3s ease;
  text-decoration: ${(props) => (props.completed ? 'line-through' : 'none')};

  &:hover {
    background-color: #e6f7ff;
  }
`;

const Text = styled.span`
  flex: 1;
  font-size: 1.2rem;
  color: ${(props) => (props.completed ? '#b0b0b0' : '#333')};
`;

const Button = styled.button`
  background-color: ${(props) => (props.completed ? '#52c41a' : '#1890ff')};
  color: white;
  border: none;
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1rem;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: ${(props) => (props.completed ? '#389e0d' : '#096dd9')};
  }
`;

const Todo = ({ todo, toggleComplete }) => {
  return (
    <TodoItem completed={todo.completed}>
      <Text completed={todo.completed}>{todo.text}</Text>
      <Button completed={todo.completed} onClick={() => toggleComplete(todo.id)}>
        {todo.completed ? '已完成' : '完成'}
      </Button>
      <Button onClick={() => deleteTodo(todo.id)}>刪除</Button>
    </TodoItem>
  );
};

export default Todo;

TodoForm.js:新增待辦事項表單元件

TodoForm 會包含一個輸入框和按鈕,讓使用者可以新增新的待辦事項。

當使用者按下新增時,會將新的事項加入待辦列表中。


import React, { useState } from 'react';
import styled from 'styled-components';

const Form = styled.form`
  display: flex;
  justify-content: space-between;
  margin-bottom: 20px;
`;

const Input = styled.input`
  flex: 1;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
  margin-right: 10px;
  font-size: 1rem;
`;

const Button = styled.button`
  background-color: #1890ff;
  color: white;
  border: none;
  padding: 10px 15px;
  border-radius: 5px;
  cursor: pointer;
  font-size: 1rem;
  transition: background-color 0.3s ease;

  &:hover {
    background-color: #096dd9;
  }
`;

const TodoForm = ({ addTodo }) => {
  const [input, setInput] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (input) {
      addTodo(input);
      setInput('');
    }
  };

  return (
    <Form onSubmit={handleSubmit}>
      <Input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        placeholder="輸入待辦事項..."
      />
      <Button type="submit">新增</Button>
    </Form>
  );
};

export default TodoForm;

完成上述的程式碼後,接下來運行 npm start 就可以看到我們的待辦事項應用程式。

也可以直接透過CodeSandbox 來線上觀看範例-Todo.js - nodebox - CodeSandbox

以上內容就是我們這次的綜合練習,複習之前的教學內容,從這專案中實作到 元件建立、props、state、事件處理、表單處理、條件渲染、列表渲染與 Styled Components,可以去檢視自己哪方便還不太熟悉。

接下來,明天將會繼續說明React的功能。

後記

本文將會同步更新到我的部落格

黃禎平 – Medium


上一篇
綜合練習-TodoList 實作(上) Day17
下一篇
React中處理副作用的利器 - useEffect - Day19
系列文
現在就學React.js 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言